View Javadoc

1   /*
2    * J.A.D.E. Java(TM) Addition to Default Environment.
3    * Latest release available at http://jade.dautelle.com/
4    * This class is public domain (not copyrighted).
5    */
6   package ch.twiddlefinger.inet.rewinder.model.parser.conversion;
7   
8   import java.io.IOException;
9   import java.io.InputStream;
10  import java.io.OutputStream;
11  import java.lang.reflect.Array;
12  import java.lang.reflect.Constructor;
13  import java.nio.ByteBuffer;
14  import java.nio.ByteOrder;
15  
16  /***
17   * <p> This class represents a <code>C/C++ struct</code>; it confers
18   *     interoperability between Java classes and C/C++ struct.</p>
19   * <p> Unlike <code>C/C++</code>, the storage layout of Java objects is not
20   *     determined by the compiler. The layout of objects in memory is deferred
21   *     to run time and determined by the interpreter (or just-in-time compiler).
22   *     This approach allows for dynamic loading and binding; but also makes
23   *     interfacing with <code>C/C++</code> code difficult. Hence, this class for
24   *     which the memory layout is defined by the initialization order of the
25   *     {@link Struct}'s {@link Member members} and follows the same alignment
26   *      rules as <code>C/C++ structs</code>.</p>
27   * <p> This class (as well as the {@link Union} sub-class) facilitates:
28   *     <ul>
29   *     <li> Memory sharing between Java applications and native libraries.</li>
30   *     <li> Direct encoding/decoding of streams for which the structure
31   *          is defined by legacy C/C++ code.</li>
32   *     <li> Serialization/deserialization of Java objects (complete control,
33   *          e.g. no class header)</li>
34   *     <li> Mapping of Java objects to physical addresses (with JNI).</li>
35   *     </ul></p>
36   * <p> Because of its one-to-one mapping, it is relatively easy to convert C 
37   *     header files (e.g. OpenGL bindings) to Java {@link Struct}/{@link Union}
38   *     using simple text macros. Here is an example of C struct:<pre>
39   *     struct Date {
40   *         unsigned short year;
41   *         unsigned char month;
42   *         unsigned char day;
43   *     };
44   *     struct Student {
45   *         char        name[64];
46   *         struct Date birth;
47   *         float       grades[10];
48   *         Student*    next;
49   *     };</pre>
50   *     and here is the Java equivalent using this class:<pre>
51   *     public static class Date extends Struct {
52   *         public final Unsigned16 year = new Unsigned16();
53   *         public final Unsigned8 month = new Unsigned8();
54   *         public final Unsigned8 day   = new Unsigned8();
55   *     }
56   *     public static class Student extends Struct {
57   *         public final UTF8String  name   = new UTF8String(64);
58   *         public final Date        birth  = (Date) new StructMember(Date.class).get();
59   *         public final Float32[]   grades = (Float32[]) new ArrayMember(Float32.class, 10).get();
60   *         public final Reference32 next   =  new Reference32(Student.class);
61   *     }</pre>
62   *     Struct's members are directly accessible:<pre>
63   *     Student student = new Student();
64   *     student.name.set("John Doe"); // Null terminated (C compatible)
65   *     int age = 2003 - student.birth.year.get();
66   *     student.grades[2].set(12.5f);
67   *     student = (Student) student.next.get();</pre></p>
68   * <p> Applications may also work with the raw {@link #byteBuffer() bytes}
69   *     directly:<pre>
70   *     Struct message = new Message();
71   *     SocketChannel socket = SocketChannel.open(address);
72   *     // Reads message.
73   *     message.byteBuffer().position(0);
74   *     socket.read(message.byteBuffer());
75   *     // Writes message.
76   *     message.byteBuffer().position(0);
77   *     socket.write(message.byteBuffer());</pre>
78   *     {@link Struct} can be used to read UDP packets directly:<pre>
79   *     class MyUdpMessage extends Struct {
80   *         ... // UDP message fields.
81   *         public MyUdpMessage(byte[] bytes) {
82   *             super(ByteBuffer.wrap(bytes));
83   *         }
84   *     }
85   *     public void run() {
86   *         byte[] bytes = new byte[1024];
87   *         DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
88   *         MyUdpMessage message = new MyUdpMessage(bytes);
89   *         // packet and message are now different views of the same data. 
90   *         while (true) {
91   *             _socket.receive(packet);
92   *             ... // Process message fields.
93   *             packet.setLength(bytes.length); // Reset length to buffer's length.
94   *         }
95   *     }</pre></p> 
96   * <p> It is relatively easy to map instances of this class to any physical
97   *     address using
98   *     <a href="http://java.sun.com/docs/books/tutorial/native1.1/index.html">
99   *     JNI</a>. Here is an example:<pre>
100  *     import java.nio.ByteBuffer;
101  *     class Clock extends Struct { // Hardware clock mapped to memory.
102  *         Unsigned16 seconds  = new Unsigned16(5); // unsigned short seconds:5
103  *         Unsigned16 minutes  = new Unsigned16(5); // unsigned short minutes:5
104  *         Unsigned16 hours    = new Unsigned16(4); // unsigned short hours:4
105  *         Clock() {
106  *             super(Clock.nativeBuffer());
107  *         }
108  *         private static native ByteBuffer nativeBuffer();
109  *     }</pre>
110  *     Below is the <code>nativeBuffer()</code> implementation
111  *     (<code>Clock.c</code>):<pre>
112  *     #include &lt;jni.h&gt;
113  *     #include "Clock.h" // Generated using javah
114  *     JNIEXPORT jobject JNICALL Java_Clock_nativeBuffer (JNIEnv *env, jclass) {
115  *         return (*env)->NewDirectByteBuffer(env, clock_address, buffer_size)
116  *     }</pre></p>
117  * <p> Finally, bit-fields are supported (see <code>Clock</code> example above).
118  *     Bit-fields allocation order is defined by the {@link Struct}'s
119  *     {@link #byteOrder byte order} (leftmost bit to rightmost bit if
120  *     <code>BIG_ENDIAN</code> and rightmost bit to leftmost bit if
121  *      <code>LITTLE_ENDIAN</code>).
122  *     Bit-fields cannot straddle the storage-unit boundary as defined by their
123  *     base type (padding is inserted at the end of the first bit-field
124  *     and the second bit-field is put into the next storage unit).</p>
125  *
126  * <p><i> This class is <b>public domain</b> (not copyrighted).</i></p>
127  *
128  * @author  <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
129  * @version 5.3, December 7, 2003
130  */
131 public abstract class Struct {
132     
133     /***
134      * Holds the current outer struct during construction process.
135      */
136     private static final ThreadLocal OUTER = new ThreadLocal();
137 
138     /***
139      * Holds the byte buffer backing the struct.
140      */
141     private ByteBuffer _byteBuffer;
142 
143     /***
144      * Holds the number of bits currently used (for size calculation).
145      */
146     private int _bitsUsed;
147 
148     /***
149      * Holds this struct alignment (largest alignment of its members).
150      */
151     private int _alignment;
152 
153     /***
154      * Holds the current bit index position (during construction).
155      */
156     private int _bitIndex;
157 
158     /***
159      * Indicates if the index has to be reset for each new field.
160      */
161     private boolean _resetIndex;
162 
163     /***
164      * Holds the outer struct if any.
165      */
166     private final Struct _outer;
167 
168     /***
169      * Holds the offset in the outer struct buffer.
170      */
171     private int _outerOffset;
172 
173     /***
174      * Default constructor. Top-level {@link Struct} created using this
175      * constructor are backed by a direct buffer. Inner {@link Struct} are 
176      * always backed by the buffer of their outer parent.
177      */
178     public Struct() {
179         this(null);
180     }
181 
182     /***
183      * Creates a {@link Struct} backed by the specified {@link ByteBuffer}.
184      * This constructor allows for the use of direct buffers mapped
185      * to memory. The address of the first field is always at position
186      * <code>0</code> in the specified buffer.
187      *
188      * @param byteBuffer the byte buffer for this {@link Struct}.
189      */
190     public Struct(ByteBuffer byteBuffer) {
191         _resetIndex = (this instanceof Union);
192         _byteBuffer = byteBuffer;
193         _outer = (Struct)OUTER.get();
194     }
195 
196     /***
197      * Returns the size in bytes of this {@link Struct}. The size includes
198      * tail padding to satisfy the {@link Struct} alignment requirement
199      * (defined by the largest alignment of its {@link Member members}).
200      *
201      * @return the C/C++ <code>sizeof(this)</code>.
202      */
203     public final int size() {
204         int nbrOfBytes = (_bitsUsed + 7) >> 3;
205         return ((nbrOfBytes % _alignment) == 0) ? nbrOfBytes : // Already aligned or packed.
206             nbrOfBytes + _alignment - (nbrOfBytes % _alignment); // Tail padding.
207     }
208 
209     /***
210      * Returns the {@link ByteBuffer} backing this {@link Struct}.
211      *
212      * <p> Changes to the buffer's content are visible in the {@link Struct},
213      *     and vice versa.</p>
214      * <p> The buffer limit is {@link #size()} and its position index is
215      *     undefined. Methods modifying the buffer position should either
216      *     synchronize on the buffer or work with a duplicate.</p>
217      * <p> The buffer of an inner {@link Struct} is a shared subsequence of
218      *     the buffer's content of its outer parent.
219      * <p> The buffer is direct if, and only if, this {@link Struct}
220      *     (or its outer {@link Struct}) is backed by a direct buffer (see
221      *     {@link #Struct(ByteBuffer)}).</p>
222      * <p> The position index of a {@link Struct.Member} within the buffer is
223      *     given by {@link Struct.Member#offset} (the first field member
224      *      starting at <code>0</code>).</p>
225      *
226      * @return the actual byte buffer for this {@link Struct}.
227      */
228     public final ByteBuffer byteBuffer() {
229         return (_byteBuffer != null) ? _byteBuffer : newBuffer();
230     }
231 
232     private synchronized ByteBuffer newBuffer() {
233         if (_byteBuffer == null) { // Avoids concurrent allocations.
234             int size = size();
235             if (_outer == null) { // Allocates a direct buffer.
236                 int capacity = isPacked() ? 
237                      // Covers misaligned 64 bits access when packed.
238                      ((( size & 0x7)==0) ? size : size + 8 - ( size & 0x7)) :    
239                      size;
240                 _byteBuffer = ByteBuffer.allocateDirect(capacity);
241                 _byteBuffer.order(byteOrder());
242             } else { // Subsequence of outer buffer.
243                 ByteBuffer outerBuffer = _outer.byteBuffer();
244                 synchronized (outerBuffer) {
245                     outerBuffer.position(_outerOffset);
246                     ByteBuffer subBuffer = outerBuffer.slice();
247                     // No need to set the limit, field access is controlled.
248                     _byteBuffer = subBuffer;
249                 }
250                 _byteBuffer.order(_outer.byteOrder());
251             }
252         }
253         return _byteBuffer;
254     }
255 
256     /***
257      * Copies the content of the specified source {@link Struct} to the
258      * specified destination {@link Struct}.
259      *
260      * @param  src the source {@link Struct}.
261      * @param  dest the destination {@link Struct}.
262      * @return <code>dest</code>
263      * @throws IllegalArgumentException if <code>dest</code> is not an instance
264      *         of <code>src.getClass()</code>,
265      */
266     public static Struct copy(Struct src, Struct dest) {
267         if (src.getClass().isInstance(dest)) {
268             ByteBuffer srcBuffer = src.byteBuffer();
269             ByteBuffer destBuffer = dest.byteBuffer();
270             synchronized (srcBuffer) {
271                 synchronized (destBuffer) {
272                     srcBuffer.position(0);
273                     destBuffer.position(0);
274                     srcBuffer.put(destBuffer);
275                 }
276             }
277             return dest;
278         } else {
279             throw new IllegalArgumentException("Instance of " + src.getClass() +
280                 " expected, found instance of " + dest.getClass());
281         }
282     }
283 
284     /***
285      * Indicates if this {@link Struct} is equal to the specified object.
286      *
287      * @param  that the object to compare for equality.
288      * @return <code>true</code> if this struct and the specified object are
289      *         both struct of same class with same content;
290      *         <code>false</code> otherwise.
291      */
292     public boolean equals(Object that) {
293         if (this.getClass() == that.getClass()) {
294             ByteBuffer thisBuffer = this.byteBuffer();
295             ByteBuffer thatBuffer = ((Struct)that).byteBuffer();
296             synchronized (thisBuffer) {
297                 synchronized (thatBuffer) {
298                     thisBuffer.position(0);
299                     thatBuffer.position(0);
300                     return thisBuffer.equals(thatBuffer);
301                 }
302             }
303         } else {
304             return false;
305         }
306     }
307 
308     /***
309      * Returns a hash code value for this {@link Struct}.
310      *
311      * <p> Note: Because {@link Struct} hash codes are content-dependent,
312      *           it is inadvisable to use {@link Struct} as keys in hash maps
313      *           or similar data structures unless it is known that their
314      *           contents will not change.</p>
315      *
316      * @return this struct hash code value.
317      */
318     public final int hashCode() {
319         ByteBuffer thisBuffer = this.byteBuffer();
320         synchronized (thisBuffer) {
321             thisBuffer.position(0);
322             return thisBuffer.hashCode();
323         }
324     }
325 
326     /***
327      * Returns this {@link Struct} address. This method allows for 
328      * {@link Struct} to be referenced (e.g. pointer) from other {@link Struct}.
329      *
330      * @return the struct memory address.
331      * @throws UnsupportedOperationException if the struct's buffer is not 
332      *         a direct buffer.
333      */
334     public final long address() {
335         ByteBuffer thisBuffer = this.byteBuffer();
336         if (thisBuffer instanceof sun.nio.ch.DirectBuffer) {
337             return ((sun.nio.ch.DirectBuffer)thisBuffer).address();
338         } else {
339            throw new UnsupportedOperationException(
340                "Operation not supported for " + thisBuffer.getClass());
341         }
342     }
343 
344     /***
345      * Returns the <code>String</code> representation of this {@link Struct}
346      * in the form of its constituing bytes (hexadecimal). For example:<pre>
347      *     public static class Student extends Struct {
348      *         UTF8String name  = new UTF8String(16);
349      *         Unsigned16 year  = new Unsigned16();
350      *         Float32    grade = new Float32();
351      *     }
352      *     Student student = new Student();
353      *     student.name.set("John Doe");
354      *     student.year.set(2003);
355      *     student.grade.set(12.5f);
356      *     System.out.println(student);
357      *
358      *     4a 6f 68 6e 20 44 6f 65 00 00 00 00 00 00 00 00
359      *     07 d3 00 00 41 48 00 00</pre>
360      *
361      * @return a hexadecimal representation of the bytes content for this
362      *         {@link Struct}.
363      */
364     public final String toString() {
365         StringBuffer stringBuffer = new StringBuffer(3 * size());
366         final int size = size();
367         final ByteBuffer buffer = byteBuffer();
368         for (int i = 0; i < size; i++) {
369             int b = buffer.get(i) & 0xFF;
370             if (b < 0x10) {
371                 // Ensures 2 digits per byte for alignment purpose.
372                 stringBuffer.append('0');
373             }
374             TypeFormat.format(b, 16, stringBuffer);
375             if ((i & 0xF) == 0xF) {
376                 // 16 bytes per line.
377                 stringBuffer.append('\n');
378             } else {
379                 stringBuffer.append(' ');
380             }
381         }
382         return stringBuffer.toString();
383     }
384 
385     ///////////////////
386     // CONFIGURATION //
387     ///////////////////
388 
389     /***
390      * Returns the byte order for this {@link Struct}. The byte order is
391      * inherited by inner structs. Sub-classes may change the byte order
392      * by overriding this method. For example:<pre>
393      * public final class TopStruct {
394      *     ... // Members initialization.
395      *     public ByteOrder byteOrder() {
396      *         // TopStruct and its inner structs use hardware byte order.
397      *         return ByteOrder.nativeOrder();
398      *    }
399      * }}</pre></p></p>
400      *
401      * @return the byte order when reading/writing multibyte values
402      *         (default: network byte order, <code>BIG_ENDIAN</code>).
403      */
404     public ByteOrder byteOrder() {
405         if (_outer != null) {
406             return _outer.byteOrder();
407         } else {
408             return ByteOrder.BIG_ENDIAN;
409         }
410     }
411 
412     /***
413      * Indicates if this {@link Struct} is packed.
414      * By default, {@link Member} of a {@link Struct} are aligned on the
415      * boundary corresponding to the member's base type; padding is performed
416      * if necessary. This directive is inherited by inner structs.
417      * Sub-classes may change the packing directive by overriding this method.
418      * For example:<pre>
419      * public final class TopStruct {
420      *     ... // Members initialization.
421      *     public boolean isPacked() {
422      *         // TopStruct and its inner structs are packed.
423      *         return true;
424      *     }
425      * }}</pre></p></p>
426      *
427      * @return <code>true</code> if alignment requirements are ignored.
428      *         <code>false</code> otherwise (default).
429      */
430     public boolean isPacked() {
431         if (_outer != null) {
432             return _outer.isPacked();
433         } else {
434             return false;
435         }
436     }
437 
438     /////////////
439     // MEMBERS //
440     /////////////
441 
442     /***
443      * This inner class represents the base class for all {@link Struct}
444      * members. It allows applications to define additional member types.
445      * For example:<pre>
446      *    public class MyStruct extends Struct {
447      *        BitSet bits = new BitSet(256);
448      *        ...
449      *        public BitSet extends Member {
450      *            public BitSet(int nbrBits) {
451      *                super(1, (nbrBits+7)>>3);
452      *            }
453      *            public boolean get(int i) { ... }
454      *            public void set(int i, boolean value) { ...}
455      *        }
456      *    }</pre>
457      */
458     protected abstract class Member { // Package private.
459 
460         /***
461          * Holds the offset of this field in the struct's buffer.
462          */
463         private int _offset;
464 
465         /***
466          * Default constructor (used internally for inner struct and bit-fields).
467          */
468         Member() {} // Package private.
469 
470         /***
471          * Base constructor for custom member types.
472          *
473          * @param  alignment the desired alignment in bytes.
474          * @param  size the size of this member in bytes.
475          */
476         protected Member(int alignment, int size) {
477             final int nbrOfBits = size << 3;
478             updateIndexes(alignment, nbrOfBits, nbrOfBits);
479         }
480 
481         /***
482          * Returns the offset of this {@link Struct.Member} in the
483          * {@link Struct}'s {@link Struct#byteBuffer() byte buffer}.
484          *
485          * @return the offset in bytes.
486          */
487         public final int offset() {
488             return _offset;
489         }
490 
491         /***
492          * Updates the {@link Struct}'s indexes and size.
493          *
494          * @param  alignment  the desired alignment in bytes.
495          * @param  nbrOfBits  the size in bits.
496          * @param  capacity   the word size maximum capacity in bits
497          *                    (equal to nbrOfBits for non-bitfields).
498          * @throws IllegalArgumentException if
499          *         <code>nbrOfBits &gt; capacity</code>
500          */
501         void updateIndexes(int alignment, int nbrOfBits, int capacity) { // Package private.
502             if (nbrOfBits > capacity) {
503                 throw new IllegalArgumentException("nbrOfBits: " + nbrOfBits +
504                     " exceeds capacity: " + capacity);
505             }
506 
507             // Resets index if union.
508             if (_resetIndex) {
509                 _bitIndex = 0;
510             }
511 
512             // Caculates offset based on alignment constraints.
513             alignment = isPacked() ? 1 : alignment;
514             _offset = (_bitIndex / (alignment << 3)) * alignment;
515             int usedBits = _bitIndex - (_offset << 3);
516 
517             // Checks if bits can be adjacents.
518             if ((capacity < usedBits + nbrOfBits) || (nbrOfBits == 0)) {
519                 // Padding to next alignment boundary.
520                 _offset += alignment;
521                 _bitIndex = (_offset << 3) + nbrOfBits;
522             } else { // Adjacent bits.
523                 _bitIndex += nbrOfBits;
524             }
525 
526             // Updates bits used (for size calculation).
527             if (_bitsUsed < _bitIndex) {
528                 _bitsUsed = _bitIndex;
529             }
530 
531             // Updates Struct's alignment.
532             if (Struct.this._alignment < alignment) {
533                 Struct.this._alignment = alignment;
534             }
535         }
536 
537         /***
538          * Creates a new instance of specified type.
539          *
540          * @param  classType the class type.
541          * @return an object of the specified class type created using its
542          *         default constructor.
543          * @throws ClassCastException if classType is not derived from
544          *         {@link Struct} or from {@link Struct.Member}.
545          */
546         Object newInstance(Class classType) { // Package private.
547             try {
548                 if (Member.class.isAssignableFrom(classType)) {
549                     // Inner Member class.
550                     Constructor[] constructors = classType.getConstructors();
551                     for (int i=0; i < constructors.length; i++) {
552                         Class[] params= constructors[i].getParameterTypes();
553                         if (    (params.length == 1) &&
554                                 Struct.class.isAssignableFrom(params[0])  ) {
555                             return constructors[i].newInstance(
556                                 new Object[] {Struct.this});
557                         }
558                     }
559                     throw new NoSuchMethodError(
560                         classType + " has no public default constructor");
561                 }
562                 // Inner struct.
563                 Struct outer = (Struct)OUTER.get();
564                 OUTER.set(Struct.this);
565                 Struct struct = (Struct)classType.newInstance();
566                 OUTER.set(outer);
567                 final int bitSize = struct.size() << 3;
568                 updateIndexes(struct._alignment, bitSize, bitSize);
569                 struct._outerOffset = (_bitIndex - bitSize) >> 3;
570                 return struct;
571 
572                 // Re-exports any exception as error.
573             } catch (InstantiationException e1) {
574                 throw new InstantiationError(e1.getMessage());
575             } catch (IllegalAccessException e2) {
576                 throw new IllegalAccessError(e2.getMessage());
577             } catch (java.lang.reflect.InvocationTargetException e3) {
578                 throw new Error(e3.getMessage());
579             }
580         }
581     }
582 
583     /***
584      * This class represents an inner struct member.
585      */
586     public final class StructMember extends Member {
587 
588         /***
589          * Holds the inner struct.
590          */
591         private final Struct _struct;
592 
593         /***
594          * Creates a {@link Struct.StructMember} having an inner struct
595          * of specified type.
596          *
597          * @param  structType the class of the inner struct.
598          * @throws ClassCastException if the specified class is not derived from
599          *         {@link Struct}.
600          */
601         public StructMember(Class structType) {
602             _struct = (Struct)newInstance(structType);
603         }
604 
605         /***
606          * Returns the struct represented by this {@link Struct.StructMember}.
607          *
608          * @return the inner struct.
609          */
610         public Struct get() {
611             return _struct;
612         }
613     }
614 
615     /***
616      * This class represents an array member. Array's element can be
617      * {@link Struct.Member} or {@link Struct}/{@link Union}. For example the
618      *  following C code:<pre>
619      *     struct Vertex {
620      *         float x;
621      *         float y;
622      *     };
623      *     struct Rectangle {
624      *         int    colors[4];
625      *         struct Vertex vertices[2][2];
626      *         char   text[4][20];
627      *     };</pre>
628      *     would be represented by:<pre>
629      *     public class Vertex extends Struct {
630      *         public final Float32 x = new Float32();
631      *         public final Float32 y = new Float32();
632      *     }
633      *     public class Rectangle extends Struct {
634      *         public final Signed32[] colors = (Signed32[]) new ArrayMember(Signed32.class, 4).get();
635      *         public final Vertex[][] vertices = (Vertex[][]) new ArrayMember(Vertex.class, new int[] {2, 2}).get();
636      *         public final UTF8String20[] text = (UTF8String20[]) new ArrayMember(UTF8String20.class, 4).get();
637      *         public class UTF8String20 extends UTF8String {
638      *             public UTF8String20() { // Default constructor (no argument) to be used.
639      *                 super(20); // UTF8String of 20 bytes.
640      *             }
641      *         }
642      *     }</pre>
643      *     Arrays elements are directly accessible:<pre>
644      *     float x01 = myRectangle.vertices[0][1].x.get();
645      *     myRectangle.colors[2].set(0xFF00FF);
646      *     myRectangle.text[0].set("Blah, Blah, Blah");</pre>
647      */
648     public final class ArrayMember extends Member {
649 
650         /***
651          * Holds the array.
652          */
653         private final Object _array;
654 
655         /***
656          * Creates an {@link Struct.ArrayMember} of specified component type.
657          *
658          * @param  componentType the component type of the array.
659          * @param  length the length of the array.
660          * @throws ClassCastException if the componentType is not derived
661          *         from {@link Struct.Member} or {@link Struct}.
662          */
663         public ArrayMember(Class componentType, int length) {
664             this(componentType, new int[] {length});
665         }
666 
667         /***
668          * Creates an {@link Struct.ArrayMember} of specified component type and
669          * dimensions.
670          *
671          * @param  componentType the component type of the array.
672          * @param  dimensions the dimensions of the array.
673          * @throws ClassCastException if the componentType is not derived
674          *         from {@link Struct.Member} or {@link Struct}.
675          */
676         public ArrayMember(Class componentType, int[] dimensions) {
677             if (_resetIndex) {
678                 _bitIndex = 0;
679                 _resetIndex = false; // Ensures elements are sequential.
680                 _array = newArray(componentType, dimensions);
681                 _resetIndex = true;
682             } else {
683                 _array = newArray(componentType, dimensions);
684             }
685         }
686 
687         private Object newArray(Class componentType, int[] dimensions) {
688             Object array = Array.newInstance(componentType, dimensions);
689             int length = dimensions[0];
690             if (dimensions.length == 1) { // Populates with componentType
691                 for (int i = 0; i < length; i++) {
692                     Object obj = newInstance(componentType);
693                     Array.set(array, i, obj);
694                 }
695             } else { // Populates with sub-arrays (recursive).
696                 final int[] innerDim = new int[dimensions.length - 1];
697                 for (int i = 1; i < dimensions.length; i++) {
698                     innerDim[i - 1] = dimensions[i];
699                 }
700                 for (int i = 0; i < length; i++) {
701                     Array.set(array, i, newArray(componentType, innerDim));
702                 }
703             }
704             return array;
705         }
706 
707         /***
708          * Returns the array represented by this {@link Struct.ArrayMember}.
709          *
710          * @return the array member.
711          */
712         public Object get() {
713             return _array;
714         }
715     }
716 
717     ///////////////////////
718     // PREDEFINED FIELDS //
719     ///////////////////////
720 
721     /***
722      * This class represents a UTF-8 character string, null terminated
723      * (for C/C++ compatibility)
724      */
725     public class UTF8String extends Member {
726         private final Utf8StreamWriter _writer;
727         private final Utf8StreamReader _reader;
728         private final char[] _charBuffer;
729 
730         public UTF8String(int length) {
731             super(1, length);
732             final int indexLast = offset() + length;
733             _writer = new Utf8StreamWriter(length);
734             _writer.setOutputStream(new OutputStream() {
735                 public void write(int b) throws IOException {
736                     final ByteBuffer buffer = byteBuffer();
737                     if (buffer.position() < indexLast) {
738                         buffer.put((byte)b);
739                     } // else discards.
740                 }
741             });
742             _reader = new Utf8StreamReader(length);
743             _reader.setInputStream(new InputStream() {
744                 public int read() throws IOException {
745                     final ByteBuffer buffer = byteBuffer();
746                     if (buffer.position() < indexLast) {
747                         byte b = buffer.get();
748                         if (b != 0) {
749                             return b;
750                         }
751                     }
752                     return -1;
753                 }
754             });
755             _charBuffer = new char[length];
756         }
757 
758         public void set(String string) {
759             final ByteBuffer buffer = byteBuffer();
760             synchronized (buffer) {
761                 try {
762                     buffer.position(offset());
763                     _writer.write(string);
764                     _writer.write(0); // Marks end of string.
765                     _writer.flush();
766                 } catch (IOException e) {
767                     throw new Error(e);
768                 }
769             }
770         }
771 
772         public String get() {
773             final ByteBuffer buffer = byteBuffer();
774             synchronized (buffer) {
775                 try {
776                     buffer.position(offset());
777                     int length = _reader.read(_charBuffer);
778                     return (length > 0) ? new String(_charBuffer, 0,
779                         length) : "";
780                 } catch (IOException e) {
781                     throw new Error(e);
782                 }
783             }
784         }
785     }
786 
787     /***
788      * This class represents a 8 bits boolean with <code>true</code> represented
789      * by <code>1</code> and <code>false</code> represented by <code>0</code>.
790      */
791     public class Bool extends Member {
792         private final int _mask;
793         private final int _shift;
794         public Bool() {
795             this(8);
796         }
797 
798         public Bool(int nbrOfBits) {
799             updateIndexes(1, nbrOfBits, 8);
800             final int startBit = offset() << 3;
801             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
802                 8 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
803             _mask = ((1 << nbrOfBits) - 1) << _shift;
804         }
805 
806         public boolean get() {
807             return (byteBuffer().get(offset()) & _mask) != 0;
808         }
809 
810         public void set(boolean value) {
811             if (_mask == 0xFF) { // Non bit-field.
812                 byteBuffer().put(offset(), (byte) (value ? 1 : 0));
813             } else { // Bit-field.
814                 int prevCleared = byteBuffer().get(offset()) & (~_mask);
815                 if (value) {
816                     byteBuffer().put(
817                         offset(), (byte) (prevCleared | (1 << _shift)));
818                 } else {
819                     byteBuffer().put(offset(), (byte) (prevCleared));
820                 }
821             }
822         }
823     }
824 
825     /***
826      * This class represents a 8 bits signed integer.
827      */
828     public class Signed8 extends Member {
829         private final int _mask;
830         private final int _shift;
831         private final int _signShift;
832         public Signed8() {
833             this(8);
834         }
835         public Signed8(int nbrOfBits) {
836             updateIndexes(1, nbrOfBits, 8);
837             final int startBit = offset() << 3;
838             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
839                 8 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
840             _mask = ((1 << nbrOfBits) - 1) << _shift;
841             _signShift = 32 - _shift - nbrOfBits;
842         }
843 
844         public byte get() {
845             if (_mask == 0xFF) { // Non bit-field.
846                 return byteBuffer().get(offset());
847             } else { // Bit-field.
848                 int value = byteBuffer().get(offset());
849                 value &= _mask;
850                 value <<= _signShift;
851                 value >>= _signShift + _shift; // Keeps sign.
852                 return (byte)value;
853             }
854         }
855 
856         public void set(byte value) {
857             if (_mask == 0xFF) { // Non bit-field.
858                 byteBuffer().put(offset(), value);
859             } else { // Bit-field.
860                 value <<= _shift;
861                 value &= _mask;
862                 int orMask = byteBuffer().get(offset()) & (~_mask);
863                 byteBuffer().put(offset(), (byte)(orMask | value));
864             }
865         }
866     }
867 
868     /***
869      * This class represents a 8 bits unsigned integer.
870      */
871     public class Unsigned8 extends Member {
872         private final int _shift;
873         private final int _mask;
874         public Unsigned8() {
875             this(8);
876         }
877 
878         public Unsigned8(int nbrOfBits) {
879             updateIndexes(1, nbrOfBits, 8);
880             final int startBit = offset() << 3;
881             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
882                 8 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
883             _mask = ((1 << nbrOfBits) - 1) << _shift;
884         }
885 
886         public short get() {
887             int value = byteBuffer().get(offset());
888             return (short)((value & _mask) >>> _shift);
889         }
890 
891         public void set(short value) {
892             if (_mask == 0xFF) { // Non bit-field.
893                 byteBuffer().put(offset(), (byte)value);
894             } else { // Bit-field.
895                 value <<= _shift;
896                 value &= _mask;
897                 int orMask = byteBuffer().get(offset()) & (~_mask);
898                 byteBuffer().put(offset(), (byte)(orMask | value));
899             }
900         }
901     }
902 
903     /***
904      * This class represents a 16 bits signed integer.
905      */
906     public class Signed16 extends Member {
907         private final int _mask;
908         private final int _shift;
909         private final int _signShift;
910         public Signed16() {
911             this(16);
912         }
913 
914         public Signed16(int nbrOfBits) {
915             updateIndexes(2, nbrOfBits, 16);
916             final int startBit = offset() << 3;
917             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
918                 16 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
919             _mask = ((1 << nbrOfBits) - 1) << _shift;
920             _signShift = 32 - _shift - nbrOfBits;
921         }
922 
923         public short get() {
924             if (_mask == 0xFFFF) { // Non bit-field.
925                 return byteBuffer().getShort(offset());
926             } else { // Bit-field.
927                 int value = byteBuffer().getShort(offset());
928                 value &= _mask;
929                 value <<= _signShift;
930                 value >>= _signShift + _shift; // Keeps sign.
931                 return (short)value;
932             }
933         }
934 
935         public void set(short value) {
936             if (_mask == 0xFFFF) { // Non bit-field.
937                 byteBuffer().putShort(offset(), value);
938             } else { // Bit-field.
939                 value <<= _shift;
940                 value &= _mask;
941                 int orMask = byteBuffer().getShort(offset()) & (~_mask);
942                 byteBuffer().putShort(offset(), (short)(orMask | value));
943             }
944         }
945     }
946 
947     /***
948      * This class represents a 16 bits unsigned integer.
949      */
950     public class Unsigned16 extends Member {
951         private final int _shift;
952         private final int _mask;
953         public Unsigned16() {
954             this(16);
955         }
956 
957         public Unsigned16(int nbrOfBits) {
958             updateIndexes(2, nbrOfBits, 16);
959             final int startBit = offset() << 3;
960             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
961                 16 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
962             _mask = ((1 << nbrOfBits) - 1) << _shift;
963         }
964 
965         public int get() {
966             int value = byteBuffer().getShort(offset());
967             return (value & _mask) >>> _shift;
968         }
969 
970         public void set(int value) {
971             if (_mask == 0xFFFF) { // Non bit-field.
972                 byteBuffer().putShort(offset(), (short)value);
973             } else { // Bit-field.
974                 value <<= _shift;
975                 value &= _mask;
976                 int orMask = byteBuffer().getShort(offset()) & (~_mask);
977                 byteBuffer().putShort(offset(), (short)(orMask | value));
978             }
979         }
980     }
981 
982     /***
983      * This class represents a 32 bits signed integer.
984      */
985     public class Signed32 extends Member {
986         private final int _mask;
987         private final int _shift;
988         private final int _signShift;
989         public Signed32() {
990             this(32);
991         }
992 
993         public Signed32(int nbrOfBits) {
994             updateIndexes(4, nbrOfBits, 32);
995             final int startBit = offset() << 3;
996             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
997                 32 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
998             _mask = (nbrOfBits == 32) ? 0xFFFFFFFF :
999                 ((1 << nbrOfBits) - 1) << _shift;
1000             _signShift = 32 - _shift - nbrOfBits;
1001         }
1002 
1003         public int get() {
1004             if (_mask == 0xFFFFFFFF) { // Non bit-field.
1005                 return byteBuffer().getInt(offset());
1006             } else { // Bit-field.
1007                 int value = byteBuffer().getInt(offset());
1008                 value &= _mask;
1009                 value <<= _signShift;
1010                 value >>= _signShift + _shift; // Keeps sign.
1011                 return value;
1012             }
1013         }
1014 
1015         public void set(int value) {
1016             if (_mask == 0xFFFFFFFF) { // Non bit-field.
1017                 byteBuffer().putInt(offset(), value);
1018             } else { // Bit-field.
1019                 value <<= _shift;
1020                 value &= _mask;
1021                 int orMask = byteBuffer().getInt(offset()) & (~_mask);
1022                 byteBuffer().putInt(offset(), orMask | value);
1023             }
1024         }
1025     }
1026 
1027     /***
1028      * This class represents a 32 bits unsigned integer.
1029      */
1030     public class Unsigned32 extends Member {
1031         private final int _shift;
1032         private final long _mask;
1033         public Unsigned32() {
1034             this(32);
1035         }
1036 
1037         public Unsigned32(int nbrOfBits) {
1038             updateIndexes(4, nbrOfBits, 32);
1039             final int startBit = offset() << 3;
1040             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
1041                 32 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
1042             _mask = (nbrOfBits == 32) ? 0xFFFFFFFFl :
1043                 ((1l << nbrOfBits) - 1l) << _shift;
1044         }
1045 
1046         public long get() {
1047             int value = byteBuffer().getInt(offset());
1048             return (value & _mask) >>> _shift;
1049         }
1050 
1051         public void set(long value) {
1052             if (_mask == 0xFFFFFFFF) { // Non bit-field.
1053                 byteBuffer().putInt(offset(), (int)value);
1054             } else { // Bit-field.
1055                 value <<= _shift;
1056                 value &= _mask;
1057                 int orMask = byteBuffer().getInt(offset()) & (~(int)_mask);
1058                 byteBuffer().putInt(offset(), (int)(orMask | value));
1059             }
1060         }
1061     }
1062 
1063     /***
1064      * This class represents a 64 bits signed integer.
1065      */
1066     public class Signed64 extends Member {
1067         private final long _mask;
1068         private final int _shift;
1069         private final int _signShift;
1070         public Signed64() {
1071             this(64);
1072         }
1073 
1074         public Signed64(int nbrOfBits) {
1075             updateIndexes(8, nbrOfBits, 64);
1076             final int startBit = offset() << 3;
1077             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
1078                 64 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
1079             _mask = (nbrOfBits == 64) ? 0xFFFFFFFFFFFFFFFFl :
1080                 ((1l << nbrOfBits) - 1l) << _shift;
1081             _signShift = 64 - _shift - nbrOfBits;
1082         }
1083 
1084         public long get() {
1085             if (_mask == 0xFFFFFFFFFFFFFFFFl) { // Non bit-field.
1086                 return byteBuffer().getLong(offset());
1087             } else { // Bit-field.
1088                 long value = byteBuffer().getLong(offset());
1089                 value &= _mask;
1090                 value <<= _signShift;
1091                 value >>= _signShift + _shift; // Keeps sign.
1092                 return value;
1093             }
1094         }
1095 
1096         public void set(long value) {
1097             if (_mask == 0xFFFFFFFFFFFFFFFFl) { // Non bit-field.
1098                 byteBuffer().putLong(offset(), value);
1099             } else { // Bit-field.
1100                 value <<= _shift;
1101                 value &= _mask;
1102                 long orMask = byteBuffer().getLong(offset()) & (~_mask);
1103                 byteBuffer().putLong(offset(), orMask | value);
1104             }
1105         }
1106     }
1107 
1108     /***
1109      * This class represents a 32 bits float (C/C++/Java <code>float</code>).
1110      */
1111     public class Float32 extends Member {
1112         public Float32() {
1113             super(4, 4);
1114         }
1115 
1116         public void set(float value) {
1117             byteBuffer().putFloat(offset(), value);
1118         }
1119 
1120         public float get() {
1121             return byteBuffer().getFloat(offset());
1122         }
1123     }
1124 
1125     /***
1126      * This class represents a 64 bits float (C/C++/Java <code>double</code>).
1127      */
1128     public class Float64 extends Member {
1129         public Float64() {
1130             super(8, 8);
1131         }
1132 
1133         public void set(double value) {
1134             byteBuffer().putDouble(offset(), value);
1135         }
1136 
1137         public double get() {
1138             return byteBuffer().getDouble(offset());
1139         }
1140     }
1141 
1142     /***
1143      * <p> This class represents a 32 bits reference (C/C++ pointer) to 
1144      *     a {@link Struct} object (other types may require a {@link Struct}
1145      *     wrapper).</p>
1146      * <p> Note: For references which can be externally modified, an application
1147      *           may want to check the {@link #isUpToDate up-to-date} status of
1148      *           the reference. For out-of-date references, a new {@link Struct}
1149      *           can be created at the address specified by {@link #value} 
1150      *           (using JNI) and then {@link #set set} to the reference.</p>
1151      */
1152     public class Reference32 extends Member {
1153         private final Class _structClass;
1154         private Struct _struct;
1155         public Reference32(Class structClass) {
1156             super(4, 4);
1157             if (Struct.class.isAssignableFrom(structClass)) {
1158                 _structClass = structClass;
1159             } else {
1160                 throw new IllegalArgumentException(
1161                      structClass + " is not a Struct/Union");
1162             }
1163         }
1164 
1165         public void set(Struct struct) {
1166             if (_structClass.isInstance(struct)) {
1167                 byteBuffer().putInt(offset(), (int) struct.address());
1168             } else if (struct == null) {
1169                 byteBuffer().putInt(offset(), 0);
1170             } else {
1171                 throw new IllegalArgumentException(
1172                     "struct: Is an instance of " + struct.getClass() + 
1173                     ", instance of " + _structClass + " expected");
1174             }
1175             _struct = struct;
1176         }
1177         public Struct get() {
1178             return _struct;
1179         }
1180         public int value() {
1181             return byteBuffer().getInt(offset());
1182         }
1183         public boolean isUpToDate() {
1184             if (_struct != null) {
1185                 return byteBuffer().getInt(offset()) == (int)_struct.address();
1186             } else {
1187                 return byteBuffer().getInt(offset()) == 0;
1188             }
1189         }
1190     }
1191     
1192     /***
1193      * <p> This class represents a 64 bits reference (C/C++ pointer) to 
1194      *     a {@link Struct} object (other types may require a {@link Struct}
1195      *     wrapper).</p>
1196      * <p> Note: For references which can be externally modified, an application
1197      *           may want to check the {@link #isUpToDate up-to-date} status of
1198      *           the reference. For out-of-date references, a new {@link Struct}
1199      *           can be created at the address specified by {@link #value} 
1200      *           (using JNI) and then {@link #set set} to the reference.</p>
1201      */
1202     public class Reference64 extends Member {
1203         private final Class _structClass;
1204         private Struct _struct;
1205         public Reference64(Class structClass) {
1206             super(8, 8);
1207             if (Struct.class.isAssignableFrom(structClass)) {
1208                 _structClass = structClass;
1209             } else {
1210                 throw new IllegalArgumentException(
1211                      structClass + " is not a Struct/Union");
1212             }
1213         }
1214 
1215         public void set(Struct struct) {
1216             if (_structClass.isInstance(struct)) {
1217                 byteBuffer().putLong(offset(), struct.address());
1218             } else if (struct == null) {
1219                 byteBuffer().putLong(offset(), 0L);
1220             } else {
1221                 throw new IllegalArgumentException(
1222                     "struct: Is an instance of " + struct.getClass() + 
1223                     ", instance of " + _structClass + " expected");
1224             }
1225             _struct = struct;
1226         }
1227         public Struct get() {
1228             return _struct;
1229         }
1230         public long value() {
1231             return byteBuffer().getLong(offset());
1232         }
1233         public boolean isUpToDate() {
1234             if (_struct != null) {
1235                 return byteBuffer().getLong(offset()) == _struct.address();
1236             } else {
1237                 return byteBuffer().getLong(offset()) == 0L;
1238             }
1239         }
1240     }
1241 
1242     /***
1243      * This class represents a 8 bits {@link Enum}.
1244      */
1245     public class Enum8 extends Member {
1246         private final int _mask;
1247         private final int _shift;
1248         private final int _signShift;
1249         private final Class _enumClass;
1250         public Enum8(Class enumClass) {
1251             this(enumClass, 8);
1252         }
1253 
1254         public Enum8(Class enumClass, int nbrOfBits) {
1255             _enumClass = enumClass;
1256             updateIndexes(1, nbrOfBits, 8);
1257             final int startBit = offset() << 3;
1258             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
1259                 8 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
1260             _mask = ((1 << nbrOfBits) - 1) << _shift;
1261             _signShift = 32 - _shift - nbrOfBits;
1262         }
1263 
1264         public Enum get() {
1265             if (_mask == 0xFF) { // Non bit-field.
1266                 return Enum.valueOf(byteBuffer().get(offset()), _enumClass);
1267             } else { // Bit-field.
1268                 int value = byteBuffer().get(offset());
1269                 value &= _mask;
1270                 value <<= _signShift;
1271                 value >>= _signShift + _shift; // Keeps sign.
1272                 return Enum.valueOf(value, _enumClass);
1273             }
1274         }
1275 
1276         public void set(Enum enum) {
1277             if (!_enumClass.isInstance(enum)) {
1278                 throw new IllegalArgumentException(
1279                     "enum: " + enum + " is not instance of " + _enumClass);
1280             }
1281             byte value = enum.byteValue();
1282             if (_mask == 0xFF) { // Non bit-field.
1283                 byteBuffer().put(offset(), value);
1284             } else { // Bit-field.
1285                 value <<= _shift;
1286                 value &= _mask;
1287                 int orMask = byteBuffer().get(offset()) & (~_mask);
1288                 byteBuffer().put(offset(), (byte)(orMask | value));
1289             }
1290         }
1291     }
1292 
1293     /***
1294      * This class represents a 16 bits {@link Enum}.
1295      */
1296     public class Enum16 extends Member {
1297         private final int _mask;
1298         private final int _shift;
1299         private final int _signShift;
1300         private final Class _enumClass;
1301         public Enum16(Class enumClass) {
1302             this(enumClass, 16);
1303         }
1304 
1305         public Enum16(Class enumClass, int nbrOfBits) {
1306             _enumClass = enumClass;
1307             updateIndexes(2, nbrOfBits, 16);
1308             final int startBit = offset() << 3;
1309             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
1310                 16 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
1311             _mask = ((1 << nbrOfBits) - 1) << _shift;
1312             _signShift = 32 - _shift - nbrOfBits;
1313         }
1314 
1315         public Enum get() {
1316             if (_mask == 0xFFFF) { // Non bit-field.
1317                 return Enum.valueOf(byteBuffer().getShort(offset()), _enumClass);
1318             } else { // Bit-field.
1319                 int value = byteBuffer().getShort(offset());
1320                 value &= _mask;
1321                 value <<= _signShift;
1322                 value >>= _signShift + _shift; // Keeps sign.
1323                 return Enum.valueOf(value, _enumClass); 
1324             }
1325         }
1326 
1327         public void set(Enum enum) {
1328             if (!_enumClass.isInstance(enum)) {
1329                 throw new IllegalArgumentException(
1330                     "enum: " + enum + " is not instance of " + _enumClass);
1331             }
1332             short value = enum.shortValue();
1333             if (_mask == 0xFFFF) { // Non bit-field.
1334                 byteBuffer().putShort(offset(), value);
1335             } else { // Bit-field.
1336                 value <<= _shift;
1337                 value &= _mask;
1338                 int orMask = byteBuffer().getShort(offset()) & (~_mask);
1339                 byteBuffer().putShort(offset(), (short)(orMask | value));
1340             }
1341         }
1342     }
1343 
1344     /***
1345      * This class represents a 32 bits {@link Enum}.
1346      */
1347     public class Enum32 extends Member {
1348         private final int _mask;
1349         private final int _shift;
1350         private final int _signShift;
1351         private final Class _enumClass;
1352         public Enum32(Class enumClass) {
1353             this(enumClass, 32);
1354         }
1355 
1356         public Enum32(Class enumClass, int nbrOfBits) {
1357             _enumClass = enumClass;
1358             updateIndexes(4, nbrOfBits, 32);
1359             final int startBit = offset() << 3;
1360             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
1361                 32 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
1362             _mask = (nbrOfBits == 32) ? 0xFFFFFFFF :
1363                 ((1 << nbrOfBits) - 1) << _shift;
1364             _signShift = 32 - _shift - nbrOfBits;
1365         }
1366 
1367         public Enum get() {
1368             if (_mask == 0xFFFFFFFF) { // Non bit-field.
1369                 return Enum.valueOf(byteBuffer().getInt(offset()), _enumClass);
1370             } else { // Bit-field.
1371                 int value = byteBuffer().getInt(offset());
1372                 value &= _mask;
1373                 value <<= _signShift;
1374                 value >>= _signShift + _shift; // Keeps sign.
1375                 return Enum.valueOf(value, _enumClass);
1376             }
1377         }
1378 
1379         public void set(Enum enum) {
1380             if (!_enumClass.isInstance(enum)) {
1381                 throw new IllegalArgumentException(
1382                     "enum: " + enum + " is not instance of " + _enumClass);
1383             }
1384             int value = enum.intValue();
1385             if (_mask == 0xFFFFFFFF) { // Non bit-field.
1386                 byteBuffer().putInt(offset(), value);
1387             } else { // Bit-field.
1388                 value <<= _shift;
1389                 value &= _mask;
1390                 int orMask = byteBuffer().getInt(offset()) & (~_mask);
1391                 byteBuffer().putInt(offset(), orMask | value);
1392             }
1393         }
1394     }
1395     /***
1396      * This class represents a 64 bits {@link Enum}.
1397      */
1398     public class Enum64 extends Member {
1399         private final long _mask;
1400         private final int _shift;
1401         private final int _signShift;
1402         private final Class _enumClass;
1403         public Enum64(Class enumClass) {
1404             this(enumClass, 64);
1405         }
1406         public Enum64(Class enumClass, int nbrOfBits) {
1407             _enumClass = enumClass;
1408             updateIndexes(8, nbrOfBits, 64);
1409             final int startBit = offset() << 3;
1410             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
1411                 64 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
1412             _mask = (nbrOfBits == 64) ? 0xFFFFFFFFFFFFFFFFl :
1413                 ((1l << nbrOfBits) - 1l) << _shift;
1414             _signShift = 64 - _shift - nbrOfBits;
1415         }
1416 
1417         public Enum get() {
1418             if (_mask == 0xFFFFFFFFFFFFFFFFl) { // Non bit-field.
1419                 return Enum.valueOf(byteBuffer().getLong(offset()), _enumClass);
1420             } else { // Bit-field.
1421                 long value = byteBuffer().getLong(offset());
1422                 value &= _mask;
1423                 value <<= _signShift;
1424                 value >>= _signShift + _shift; // Keeps sign.
1425                 return Enum.valueOf(value, _enumClass);
1426             }
1427         }
1428 
1429         public void set(Enum enum) {
1430             if (!_enumClass.isInstance(enum)) {
1431                 throw new IllegalArgumentException(
1432                     "enum: " + enum + " is not instance of " + _enumClass);
1433             }
1434             long value = enum.longValue();
1435             if (_mask == 0xFFFFFFFFFFFFFFFFl) { // Non bit-field.
1436                 byteBuffer().putLong(offset(), value);
1437             } else { // Bit-field.
1438                 value <<= _shift;
1439                 value &= _mask;
1440                 long orMask = byteBuffer().getLong(offset()) & (~_mask);
1441                 byteBuffer().putLong(offset(), orMask | value);
1442             }
1443         }
1444     }
1445 }